# Copyright 2023 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.

load(
    "@pw_toolchain//cc_toolchain:defs.bzl",
    "ALL_CPP_COMPILER_ACTIONS",
    "ALL_C_COMPILER_ACTIONS",
    "ALL_LINK_ACTIONS",
    "pw_cc_flag_set",
    "pw_cc_toolchain",
)
load("@pw_xcode_command_line_tools//:defs.bzl", "XCODE_SDK_PATH")

package(default_visibility = ["//visibility:public"])

licenses(["notice"])

filegroup(name = "empty")

pw_cc_flag_set(
    name = "macos_stdlib",
    actions = ALL_LINK_ACTIONS,
    flags = ["external/llvm_toolchain/lib/libc++.a"],
    target_compatible_with = ["@platforms//os:macos"],
)

pw_cc_flag_set(
    name = "linux_link_libs",
    actions = ALL_LINK_ACTIONS,
    flags = [
        "-pthread",
        "-stdlib=libc++",
        "--rtlib=compiler-rt",
        "--unwindlib=libunwind",
    ],
    target_compatible_with = ["@platforms//os:linux"],
)

# Although we use similar warnings for clang and arm_gcc, we don't have one
# centralized list, since we might want to use different warnings based on the
# compiler in the future.
pw_cc_flag_set(
    name = "warnings",
    actions = ALL_C_COMPILER_ACTIONS + ALL_CPP_COMPILER_ACTIONS,
    flags = [
        "-Wall",
        "-Wextra",
        # Make all warnings errors, except for the exemptions below.
        "-Werror",
        "-Wno-error=cpp",  # preprocessor #warning statement
        "-Wno-error=deprecated-declarations",  # [[deprecated]] attribute
    ],
)

# Thread safety warnings are only supported by Clang.
pw_cc_flag_set(
    name = "thread_safety_warnings",
    actions = ALL_C_COMPILER_ACTIONS + ALL_CPP_COMPILER_ACTIONS,
    flags = [
        "-Wthread-safety",
        "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS=1",
    ],
)

pw_cc_flag_set(
    name = "no_unknown_warning_option",
    actions = ALL_C_COMPILER_ACTIONS + ALL_CPP_COMPILER_ACTIONS,
    flags = [
        "-Wno-unknown-warning-option",
    ],
)

filegroup(
    name = "sysroot_files",
    srcs = select({
        "@platforms//os:linux": [
            "@linux_sysroot//:all",
        ],
        "//conditions:default": [],
    }),
)

pw_cc_toolchain(
    name = "host_toolchain",
    action_config_flag_sets = select({
        "@platforms//os:macos": [
            "@pw_toolchain//flag_sets:no_default_cpp_stdlib",
            ":macos_stdlib",
        ],
        "@platforms//os:linux": [
            ":linux_link_libs",
        ],
    }) + [
        ":warnings",
        ":thread_safety_warnings",
        "@pw_toolchain//flag_sets:c++17",
        "@pw_toolchain//flag_sets:debugging",
        "@pw_toolchain//flag_sets:reduced_size",
        "@pw_toolchain//flag_sets:no_canonical_prefixes",
        "@pw_toolchain//flag_sets:no_rtti",
        "@pw_toolchain//flag_sets:wno_register",
        "@pw_toolchain//flag_sets:wnon_virtual_dtor",
    ] + select({
        "//pw_build:kythe": [":no_unknown_warning_option"],
        "//conditions:default": [],
    }),
    action_configs = [
        "@llvm_toolchain//:ar",
        "@llvm_toolchain//:clang",
        "@llvm_toolchain//:clang++",
        "@llvm_toolchain//:lld",
        "@llvm_toolchain//:llvm-cov",
        "@llvm_toolchain//:llvm-objcopy",
        "@llvm_toolchain//:llvm-objdump",
        "@llvm_toolchain//:llvm-strip",
    ],
    builtin_sysroot = select({
        "@platforms//os:macos": XCODE_SDK_PATH,
        "@platforms//os:linux": "external/linux_sysroot",
    }),
    compiler_files = ":sysroot_files",
    cxx_builtin_include_directories = select({
        "@platforms//os:macos": [
            "%sysroot%/usr/include",
            "%package(@llvm_toolchain//)%/include/c++/v1",
            "%package(@llvm_toolchain//)%/lib/clang/18/include",
        ],
        "@platforms//os:linux": [
            "%package(@llvm_toolchain//)%/include/x86_64-unknown-linux-gnu/c++/v1",
            "%package(@llvm_toolchain//)%/include/c++/v1",
            "%package(@llvm_toolchain//)%/lib/clang/18/include",
            "%sysroot%/usr/local/include",
            "%sysroot%/usr/include/x86_64-linux-gnu",
            "%sysroot%/usr/include",
        ],
    }),
    linker_files = ":sysroot_files",
    supports_param_files = 0,
    # The implementations of some "legacy features" built into Bazel use
    # `target_libc` to determine if a toolchain targets MacOS,
    # https://github.com/bazelbuild/bazel/blob/release-7.0.0-pre.20230816.3rc1/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java#L1301-L1304
    target_cpu = select({
        "@platforms//os:macos": "darwin",
        "//conditions:default": None,
    }),
    target_libc = select({
        "@platforms//os:macos": "macosx",
        "//conditions:default": None,
    }),
    toolchain_identifier = "host-toolchain",
)

toolchain(
    name = "host_cc_toolchain_linux",
    exec_compatible_with = [
        "@platforms//os:linux",
    ],
    target_compatible_with = [
        "@platforms//os:linux",
    ],
    toolchain = ":host_toolchain",
    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)

toolchain(
    name = "host_cc_toolchain_macos",
    exec_compatible_with = [
        "@platforms//os:macos",
    ],
    target_compatible_with = [
        "@platforms//os:macos",
    ],
    toolchain = ":host_toolchain",
    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)
